import { Matrix4 } from "../../utils/Matrix4";
import { Primitives } from "../../utils/Primitives";
import { TextrueUtil } from "../../utils/TextureUtil";
import { Util } from "../../utils/Util";
import { WebGLUtil } from "../../utils/WebGLUtil";
import { Render } from "../Render";
import { WebglTemplateBase } from "../template/WebglTemplateBase";

/*
 * @Author: Snow
 * @Date: 2021-10-11 20:35:00
 * @Description: 3D纹理
 */
export class TextureCube extends WebglTemplateBase {
    protected override initProgram(): void {
        this.vsSource = `
            attribute vec4 a_position;
            attribute vec2 a_texcoord;
            
            uniform mat4 u_matrix;
            
            varying vec2 v_texcoord;
            
            void main() {
                // Multiply the position by the matrix.
                gl_Position = u_matrix * a_position;
                
                // Pass the texcoord to the fragment shader.
                v_texcoord = a_texcoord;
            }
        `;

        this.fsSource = `
            precision mediump float;

            // Passed in from the vertex shader.
            varying vec2 v_texcoord;
            
            // The texture.
            uniform sampler2D u_texture;
            
            void main() {
                gl_FragColor = texture2D(u_texture, v_texcoord);
            }
        `;
        super.initProgram();
    }

    protected override initBuffers(): void {
        super.initBuffers();
        const gl = Render.GL;

        var positions = [
            -0.5, -0.5, -0.5,
            -0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,
            -0.5, 0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,

            -0.5, -0.5, 0.5,
            0.5, -0.5, 0.5,
            -0.5, 0.5, 0.5,
            -0.5, 0.5, 0.5,
            0.5, -0.5, 0.5,
            0.5, 0.5, 0.5,

            -0.5, 0.5, -0.5,
            -0.5, 0.5, 0.5,
            0.5, 0.5, -0.5,
            -0.5, 0.5, 0.5,
            0.5, 0.5, 0.5,
            0.5, 0.5, -0.5,

            -0.5, -0.5, -0.5,
            0.5, -0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, -0.5, 0.5,
            0.5, -0.5, -0.5,
            0.5, -0.5, 0.5,

            -0.5, -0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, 0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, 0.5, 0.5,
            -0.5, 0.5, -0.5,

            0.5, -0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, 0.5,
            0.5, -0.5, 0.5,
            0.5, 0.5, -0.5,
            0.5, 0.5, 0.5,

        ];

        // let tempMatrix = Matrix4.translation(-50, -75, -15);

        // for (let ii = 0; ii < positions.length; ii += 3) {
        //     var vector = Matrix4.transformPoint(tempMatrix, [positions[ii + 0], positions[ii + 1], positions[ii + 2], 1]);
        //     positions[ii + 0] = vector[0];
        //     positions[ii + 1] = vector[1];
        //     positions[ii + 2] = vector[2];
        // }

        let texcoords = [
            // select the top left image
            0, 0,
            0, 0.5,
            0.25, 0,
            0, 0.5,
            0.25, 0.5,
            0.25, 0,
            // select the top middle image
            0.25, 0,
            0.5, 0,
            0.25, 0.5,
            0.25, 0.5,
            0.5, 0,
            0.5, 0.5,
            // select to top right image
            0.5, 0,
            0.5, 0.5,
            0.75, 0,
            0.5, 0.5,
            0.75, 0.5,
            0.75, 0,
            // select the bottom left image
            0, 0.5,
            0.25, 0.5,
            0, 1,
            0, 1,
            0.25, 0.5,
            0.25, 1,
            // select the bottom middle image
            0.25, 0.5,
            0.25, 1,
            0.5, 0.5,
            0.25, 1,
            0.5, 1,
            0.5, 0.5,
            // select the bottom right image
            0.5, 0.5,
            0.75, 0.5,
            0.5, 1,
            0.5, 1,
            0.75, 0.5,
            0.75, 1,

        ];


        // an indexed quad
        let arrays = {
            position: { numComponents: 3, data: positions, },
            texcoord: { numComponents: 2, data: texcoords, },
        };


        let bufferInfo = WebGLUtil.createBufferInfoFromArrays(gl, arrays);

        let cameraAngleRadians = Util.degToRad(0);
        let fieldOfViewRadians = Util.degToRad(60);
        let cameraHeight = 50;

        let textures = [
            TextrueUtil.makeStripeTexture(gl, { color1: "#FFF", color2: "#CCC", }),
            TextrueUtil.makeCheckerTexture(gl, { color1: "#FFF", color2: "#CCC", }),
            TextrueUtil.makeCircleTexture(gl, { color1: "#FFF", color2: "#CCC", }),
        ];



        // Create a texture.
        let texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, texture);
        // Fill the texture with a 1x1 blue pixel.
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
            new Uint8Array([0, 0, 255, 255]));
        // Asynchronously load an image

        let image = new Image();
        //image.src = "f-texture.png";
        image.src = "noodles.jpg";
        image.addEventListener('load', function () {
            // Now that the image has loaded make copy it to the texture.
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
            if (Util.isPowerOf2(image.width) && Util.isPowerOf2(image.height)) {
                gl.generateMipmap(gl.TEXTURE_2D);
            } else {
                // 不是 2 的幂，关闭贴图并设置包裹模式为到边缘
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            }

        });

        let uniforms = {
            u_texture: texture,
            u_matrix: null,
        }


        let drawScene = () => {
            let time = this.ts;
            time = time;
            WebGLUtil.resizeCanvasToMatchDisplaySize(gl);
            // Clear the canvas AND the depth buffer.
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            // Compute the projection matrix
            let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            var projectionMatrix = Matrix4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            // Compute the camera's matrix using look at.
            let cameraPosition = [0, 0, 3];
            let target = [0, 0, 0];
            let up = [0, 1, 0];
            let cameraMatrix = Matrix4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            let viewMatrix = Matrix4.invert(cameraMatrix);

            let viewProjectionMatrix = Matrix4.multiply(projectionMatrix, viewMatrix);

            let sphereXRotation = time;
            let sphereYRotation = time;
            let cubeXRotation = -time;
            let cubeYRotation = time;
            let coneXRotation = time;
            let coneYRotation = -time;

            gl.useProgram(this.programInfo.program);

            let computeMatrix = (viewProjectionMatrix, translation, xRotation, yRotation): number[] => {
                let matrix = Matrix4.multiply(viewProjectionMatrix, Matrix4.translation(
                    translation[0],
                    translation[1],
                    translation[2]));
                matrix = matrix = Matrix4.multiply(matrix, Matrix4.rotateX(xRotation));
                return matrix = matrix = Matrix4.multiply(matrix, Matrix4.rotateY(yRotation));
            }

            // Setup all the needed buffers and attributes.
            WebGLUtil.setBuffersAndAttributes(gl, this.programInfo, bufferInfo);

            uniforms.u_matrix = computeMatrix(viewProjectionMatrix, [0, 0, 0], sphereXRotation, sphereYRotation)

            // Set the uniforms that are the same for all objects.
            WebGLUtil.setUniforms(this.programInfo, uniforms);

            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numElements);
        }
        this.draw = drawScene;
    }
}